package com.nuc.zyt.framework.context.support;

import com.nuc.zyt.framework.beans.BeanDefinition;
import com.nuc.zyt.framework.beans.PropertyValue;
import com.nuc.zyt.framework.beans.factory.support.BeanDefinitionRegistry;
import com.nuc.zyt.framework.beans.factory.support.XmlBeanDefinitionReader;
import com.nuc.zyt.framework.utils.StringUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @ClassName ClassPathXmlApplicationContext
 * @Description 用于加载类路劲下xml配置文件 具体子类
 * @Author 耀酱
 * @Date 2023/6/5 20:26
 * @Version 1.0
 */

public class ClassPathXmlApplicationContext extends AbstractApplicationContext{

    public ClassPathXmlApplicationContext(String configLocation){
        this.configLocation = configLocation;
        beanDefinitionReader = new XmlBeanDefinitionReader(); // 具体解析策略
        try{
            this.refresh();
        }catch (Exception e){

        }

    }

    // 重写BeanFactory接口的 getBean()方法

    /**
     * 这是一个简单的依赖注入容器实现方法中的 getBean 方法。该方法根据传入的 name 参数获取对应的 Bean，如果找到直接返回，否则进行对象实例化和依赖注入，
     * 最后将其存储在 Map 容器中并返回。
     *
     * 具体流程如下：
     *
     * 从 Map 容器 singletonObjects 中查找指定名称的 Bean，如果已经存在则直接返回。
     * 如果没有找到，则通过 BeanDefinitionRegistry 和 BeanDefinition 对象获取要创建的对象的类名 className。
     * 使用 Class.forName() 方法加载指定类，并调用其无参构造函数实例化对象。
     * 遍历 BeanDefinition 对象中的属性值列表 propertyValues，对于每个属性值进行依赖注入：
     * 如果属性值有 ref 属性，则通过递归调用 getBean(ref) 方法获取其依赖的 Bean 对象，并使用反射调用目标对象的 setter 方法进行注入；
     * 如果属性值有 value 属性，则直接使用反射调用目标对象的 setter 方法进行注入。
     * 将实例化后的 Bean 对象存储到 Map 容器 singletonObjects 中，并返回。
     * 需要注意的是，该实现只适用于无参构造函数的 Bean 对象，而且没有考虑循环依赖等高级应用场景，仅作为依赖注入容器实现的基础示例。
     * @param name
     * @return
     * @throws Exception
     */
    @Override
    public Object getBean(String name) throws Exception {
        // 容器有对象直接返回，否则创建
        Object o = singletonObjects.get(name);
        if(o != null){
            return o;
        }
        // 实例化对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        // 获取class
        String className = beanDefinition.getClassName();
        Class<?> aClass = Class.forName(className);
        Constructor<?> constructor = aClass.getConstructor();
        Object o1 = constructor.newInstance();

        // 依赖注入
        for (PropertyValue propertyValue : beanDefinition.getPropertyValues()) {
            String name1 = propertyValue.getName();
            String ref = propertyValue.getRef();
            String value = propertyValue.getValue();
            if(ref != null && ref != ""){
                Object bean = getBean(ref); // 递归调用依赖项

                String setterMethodByFieldName = StringUtils.getSetterMethodByFieldName(name1);
                for (Method method : aClass.getMethods()) {
                    if(method.getName().equals(setterMethodByFieldName)){
                        method.invoke(o1,bean);
                    }
                }
            }
            if(value != null && !"".equals(value)){
                String methodName = StringUtils.getSetterMethodByFieldName(name1);
                Method method = aClass.getMethod(methodName, String.class);
                method.invoke(o1,value);

            }

        }

        // 返回对象之前，将其存储到map容器
        singletonObjects.put(name,o1);
        return o1;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
        Object bean = getBean(name);
        if(bean == null){
            return null;
        }
        return clazz.cast(bean); // 类型转换方法
    }
}
